package com.xfcy.blog.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xfcy.blog.common.R;
import com.xfcy.blog.common.constant.*;
import com.xfcy.blog.common.enums.PublishEnum;
import com.xfcy.blog.entity.Article;
import com.xfcy.blog.entity.Page;
import com.xfcy.blog.entity.SystemConfig;
import com.xfcy.blog.entity.WebConfig;
import com.xfcy.blog.mapper.*;
import com.xfcy.blog.service.SystemConfigService;
import com.xfcy.blog.service.UserLogService;
import com.xfcy.blog.service.WebConfigService;
import com.xfcy.blog.utils.IpUtils;
import com.xfcy.blog.utils.LocalDateTimeUtils;
import com.xfcy.blog.vo.CategoryCountVO;
import com.xfcy.blog.vo.CategoryVO;
import com.xfcy.blog.vo.ContributeVO;
import com.xfcy.blog.vo.HomeVO;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author 晓风残月Lx
 * @date 2023/4/11 19:21
 */
@Slf4j
@Service
public class HomeServiceImpl {

    @Resource
    private WebConfigService webConfigService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private ArticleMapper articleMapper;

    @Resource
    private TagsMapper tagsMapper;

    @Resource
    private CategoryMapper categoryMapper;

    @Resource
    private PageMapper pageMapper;

    @Resource
    private UserLogMapper userLogMapper;

    @Resource
    private SystemConfigService systemConfigService;

    @Resource
    private MessageMapper messageMapper;

    @Resource
    private UserMapper userMapper;




    /**
     * 服务监控列表
     * @return
     */
    public R systemInfo() {
        return R.success();
    }

    /**
     * 首页文章、ip用户、留言统计
     * @return
     */
    public Object lineCount() {
        Map<String, Integer> map = new HashMap<>();
        map.put("article", articleMapper.selectList(null).size());
        map.put("message", messageMapper.selectList(null).size());
        map.put("user", userMapper.selectList(null).size());
        map.put("viewCount", (Integer) getViewsCount());
        return map;
    }


    /**
     * 获取各种统计信息
     * @return
     */
    public HomeVO init() {
        //文章排行
        List<Article> articles = articleMapper.selectList(new LambdaQueryWrapper<Article>()
                .select(Article::getQuantity, Article::getTitle, Article::getId)
                .eq(Article::getIsPublish, PublishEnum.PUBLISH.getCode())
                .orderByDesc(Article::getQuantity)
                .last(SqlConstant.LIMIT_SIX));
        // 文章贡献度
        Map<String, Object> contribute = this.contribute();
        // 分类统计
        Map<String, Object> categoryList = this.categoryCount();
        // 标签查询
        List<Map<String, Object>> tagList = tagsMapper.countTags();
        // 7天的用户访问量
        List<Map<String, Object>> userAccess = this.userAccess();
        // 弹出框
        SystemConfig customizeOne = systemConfigService.getCustomizeOne();

        HomeVO vo = HomeVO.builder().dashboard(customizeOne.getDashboardNotification())
                .categoryList(categoryList)
                .contribute(contribute)
                .tagsList(tagList)
                .articles(articles)
                .userAccess(userAccess)
                .build();

        return vo;
    }













    // Web 端开始

    /**
     * 获取站点信息
     */
    public R webSiteInfo() {
        //网站信息
        WebConfig webConfig = webConfigService.getOne(new LambdaQueryWrapper<WebConfig>()
                .select(WebConfig::getAuthorAvatar,WebConfig::getIsMusicPlayer,WebConfig::getAuthorInfo,WebConfig::getTouristAvatar,WebConfig::getBulletin,
                        WebConfig::getQqNumber,WebConfig::getGitee,WebConfig::getGithub,WebConfig::getLogo,
                        WebConfig::getAboutMe,WebConfig::getEmail,WebConfig::getShowList,WebConfig::getLoginTypeList,
                        WebConfig::getRecordNum,WebConfig::getAuthor,WebConfig::getAliPay,WebConfig::getWeixinPay,
                        WebConfig::getWebUrl, WebConfig::getSummary,WebConfig::getName,WebConfig::getKeyword)
                .last(SqlConstant.LIMIT_ONE));

        // 文章分类标签
        Integer articleCount = articleMapper.selectCount(new QueryWrapper<Article>().eq(SqlConstant.IS_PUBLISH, PublishEnum.PUBLISH.getCode()));
        Integer tagCount = tagsMapper.selectCount(null);
        Integer categoryCount = categoryMapper.selectCount(null);

        // 查询访问量
        String viewCount = getViewsCount().toString();

        Map<String,Object> map = new HashMap<>();
        map.put("articleCount",articleCount);
        map.put("categoryCount",categoryCount);
        map.put("tagCount",tagCount);
        map.put("viewsCount",viewCount);

        // 查询页面信息
        List<Page> pageList = pageMapper.selectList(new LambdaQueryWrapper<Page>()
                .select(Page::getPageCover, Page::getPageLabel));

        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("pageList",pageList);
        resultMap.put("webSite",webConfig);
        resultMap.put("count",map);

        return R.success(resultMap);
    }

    /**
     * 获取网站访问量
     * @return
     */
    private Object getViewsCount() {
        Object count = redisTemplate.opsForValue().get(RedisConstant.BLOG_VIEWS_COUNT);
        Object viewCounts = Optional.ofNullable(count).orElse(Constant.ZERO);
        return viewCounts;
    }

    /**
     * 记录
     * @param request
     * @return
     */
    public R report(HttpServletRequest request) {
        // 获取ip
        String ipAddress = IpUtils.getIp(request);
        // 获取访问设备
        UserAgent userAgent = IpUtils.getUserAgent(request);
        // 获取客户端浏览器
        Browser browser = userAgent.getBrowser();
        // 获取客户端操作系统
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();

        // 生成唯一用户标识
        String uuid = ipAddress + browser.getName() + operatingSystem.getName();
        String md5 = DigestUtils.md5DigestAsHex(uuid.getBytes());

        Long hll = redisTemplate.opsForHyperLogLog().add(RedisConstant.UNIQUE_VISITOR, md5);

        if (!hll.equals(Constant.LONG_ZERO)) {
            // 统计游客地域分布  中国|0|福建省|厦门市|电信
            String searchInfo = IpUtils.getCityInfo(ipAddress);
            if (StringUtils.isNotBlank(searchInfo)) {
                String[] splitIpInfo = searchInfo.split("\\|");
                // 中国福建省厦门市
                String cityInfo = splitIpInfo[0] + splitIpInfo[2] + splitIpInfo[3];
                redisTemplate.opsForHash().increment(RedisConstant.VISITOR_AREA, cityInfo, Constant.LONG_ONE);
            } else {
                redisTemplate.opsForHash().increment(RedisConstant.VISITOR_AREA, IpConstant.UNKNOWN, Constant.LONG_ONE);
            }
        }
        // 网页浏览量 +1
        redisTemplate.opsForValue().increment(RedisConstant.BLOG_VIEWS_COUNT, Constant.LONG_ONE);
        return R.success();
    }

    /**
     * 缓存监控 （redis）
     * @return
     */
    public R getCacheInfo() {
        Properties info =  (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info());
        Properties commandstats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());

        Map<String, Object> result = new HashMap<>(3);
        result.put("info", info);
        result.put("dbSize", dbSize);

        List<Map<String, String>> pieList = new ArrayList<>();
        commandstats.stringPropertyNames().forEach(key -> {
            Map<String, String> data = new HashMap<>(2);
            String property = commandstats.getProperty(key);
            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
            pieList.add(data);
        });
        result.put("commandStats", pieList);
        return R.success(result);
    }





    //--------------自定义方法开始---------------

    /**
     * 获取文章贡献度
     * @return
     */
    private Map<String, Object> contribute() {
        Map<String, Object> map = new HashMap<>();
        List<Object> contributes = new ArrayList<>();
        List<Object> result = new ArrayList<>();
        List<String> months = getMonths();
        String lastTime = months.get(0), nowTime = months.get(months.size() - 1);
        List<ContributeVO> articles = articleMapper.contribute(lastTime, nowTime);
        months.forEach(item -> {
            List<Object> list = new ArrayList<>();
            list.add(item);
            List<ContributeVO> contributeVOS = articles.stream().filter(article -> article.getDate().equals(item))
                    .collect(Collectors.toList());
            if (!contributeVOS.isEmpty()) {
                list.add(contributeVOS.get(0).getCount());
            } else {
                list.add(0);
            }
            result.add(list);
        });
        contributes.add(lastTime);
        contributes.add(nowTime);
        map.put("contributeDate", contributes);
        map.put("blogContributeCount", result);
        return map;
    }

    public static List<String> getMonths() {
        List<String> dateList = new ArrayList<String>();
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, -1);
        dateList.add(LocalDateTimeUtils.formate(calendar.getTime(), DateConstant.FORMAT_DATE));
        while (date.after(calendar.getTime())) { //倒序时间,顺序after改before其他相应的改动。
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            dateList.add(LocalDateTimeUtils.formate(calendar.getTime(), DateConstant.FORMAT_DATE));
        }
        return dateList;
    }


    /**
     * 7天的用户访问量
     * @return
     */
    private List<Map<String, Object>> userAccess() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - 7);
        List<Map<String,Object>> userAccess = userLogMapper.getUserAccess(LocalDateTimeUtils.formate(calendar.getTime(), DateConstant.FORMAT_DATE));
        return userAccess;
    }


    /**
     * 分类统计
     * @return
     */
    private Map<String, Object> categoryCount() {
        Map<String, Object> map = new HashMap<>();
        List<CategoryCountVO> result = categoryMapper.countArticle();
        List<String> list = new ArrayList<>();
        result.forEach(item -> list.add(item.getName()));
        map.put("result", result);
        map.put("categoryList", list);
        return map;
    }

}
